// import {reactive} from "vue"
import {reactive, computed, ref,toRaw} from "vue"
import {pick,omit,assignIn} from "lodash-unified";
import {Type,Exclude, Expose} from "class-transformer";
import {clearAndPushAll} from "@/utils/ArrayUtil";
import { IsString,IsArray } from 'class-validator';
import 'reflect-metadata'
import {v4 as uuidv4} from "uuid";
import {result} from "lodash";



// @Exclude()
class PhraseOWordUsage {

    @Type(()=>PhraseOWordUsage.PhraseOWord)
    // @Type(()=>PhraseOWordUsage.PhraseOWordArray)
    // @IsArray()
    _pickedPhrasesOWords;

    @Type(()=>PhraseOWordUsage.PhraseOWord)_pickedWords;

    constructor(liju,id) {
        // if (!liju?.eng || liju.eng.trim === "") {
        //     throw new Error('eng cannot be empty');
        // }

        this._id = id;

        this._pickedPhrasesOWords = reactive(new PhraseOWordUsage.PhraseOWordArray());
        this._pickedWords = reactive(new PhraseOWordUsage.PhraseOWordArray());
        this.isPickCompleted = ref(true);
        // this.phrMarkingViewName = ref("PhraseOWordNonPickMarkingView");
        //todo mark★★★★★ computed 只对reactive，ref的才会生效
        this.phrMarkingViewName = computed(() => {
            // console.log("computing the phrMarkingViewNma");
            //todo mark★★★★★ this.isPickCompleted 在没有被外层reactive包裹时，需要通过value访问。否则不用value直接访问。
            return this.isPickCompleted.value ? "PhraseOWordNonPickMarkingView" : "PhraseOWordPickMarkingView";
        });
        this._liju = liju;
        // this.aviewName = ref(this.phrMarkingViewName);
    }

    toPersistRaw(){
        let resultObj ={};
        assignIn(resultObj,this);
        resultObj._pickedPhrasesOWords = [...toRaw(this._pickedPhrasesOWords)].map(entry=>entry.toPersistRaw());
        return pick(resultObj,['_eng','_chi','_pickedPhrasesOWords']);
    }


    get liju() {
        return this._liju;
    }

    set liju(value) {
        this._liju = value;
    }

// @Expose()
    get eng() {
        return this._liju.eng;
    }

    // set eng(value) {
    //     this._eng = value;
    // }

    // @Expose()
    get chi() {
        return this._liju.chi;
    }

    // set chi(value) {
    //     this._chi = value;
    // }


    // @Expose()
    get id() {
        return this._id;
    }

    set id(value) {
        this._id = value;
    }

    @Expose()
    get pickedPhrasesOWords() {
        return this._pickedPhrasesOWords;
    }

    @Type(()=>PhraseOWordUsage.PhraseOWord)
    set pickedPhrasesOWords(value) {
        // value.forEach(pickedPhraseOWord=>pickedPhraseOWord.liju = this._liju);
        clearAndPushAll(this._pickedPhrasesOWords,value)
        // console.log("setting pickedPhrasesOWords",value)
        // this._pickedPhrasesOWords = value;
    }



    /**
     *
     * @param thePhraseOWord {PhraseOWordUsage.PhraseOWord}
     */
    addPhraseOWord(thePhraseOWord) {
        // console.log("adding the phraseOWord",thePhraseOWord);
        this._pickedPhrasesOWords.push(thePhraseOWord.clone());
    }

    removePhraseOWord(start, end) {
        this._pickedPhrasesOWords.remove(new PhraseOWordUsage.PhraseOWord(
            new PhraseOWordUsage.WordMark(start),
            new PhraseOWordUsage.WordMark(end),
            null,
            false));
    }

    anyInPickedPhase(wordStartIdx) {
        return this._pickedPhrasesOWords.some((aa) => {
            return wordStartIdx >= aa.phraseOWordStartIndex && wordStartIdx < aa.phraseOWordEndIndex;
        });
        // return theIdx>-1;
    }
}

// @Exclude()
PhraseOWordUsage.PhraseOWord = class {

    @Type(()=>PhraseOWordUsage.WordMark)
    _startWordMark;
    @Type(()=>PhraseOWordUsage.WordMark)
    _endWordMark;

    _isValidPhraseOWord;

    _uniqueId;

    _remarksAll;

    _relatedCoreConcepts;

    constructor(startWordMark, endWordMark, liju, isValidPhraseOWord = true) {

        if (isValidPhraseOWord === undefined) {
            isValidPhraseOWord = true;
        }

        if (startWordMark&&endWordMark&&isValidPhraseOWord && (startWordMark.startIdx === -1 || !startWordMark.word || endWordMark.startIdx === -1 || !endWordMark)) {
            throw new Error('invalid phraseOWord');
        }


        this._isValidPhraseOWord = isValidPhraseOWord;

        /**
         *
         * @type {String}
         */
        // this.phraseOWordKeyIdxPair = null;
        // if (startWordMark&&endWordMark&&startWordMark.startIdx !== -1 && endWordMark.startIdx !== -1) {
        //     this._phraseOWordKeyIdxPair = startWordMark.startIdx + "_" + endWordMark.startIdx;
        // }
        this._startWordMark = startWordMark;
        this._endWordMark = endWordMark;
        this._liju = liju;
        this._remarksAll = [];
        this._relatedCoreConcepts = [];
        this._uniqueId = uuidv4();
    }


    get uniqueId() {
        return this._uniqueId;
    }

    set uniqueId(value) {
        this._uniqueId = value;
    }

    get liju() {
        return this._liju;
    }

    set liju(value) {
        this._liju = value;
    }


    get isValidPhraseOWord() {
        return this._isValidPhraseOWord;
    }

    set isValidPhraseOWord(value) {
        this._isValidPhraseOWord = value;
    }

    toPersistRaw(){
        let resultObj ={};
        resultObj._startWordMark = this._startWordMark.toPersistRaw();
        resultObj._endWordMark = this._endWordMark.toPersistRaw();
        return  resultObj;
    }


    @Expose()
    get remarksAll() {
        return this._remarksAll;
    }

    set remarksAll(value) {
        clearAndPushAll(this._remarksAll,value);
        // this._remarksAll = value;
    }


    @Expose()
    get relatedCoreConcepts() {
        return this._relatedCoreConcepts;
    }

    set relatedCoreConcepts(value) {
        // this._relatedCoreConcepts = value;
        clearAndPushAll(this._relatedCoreConcepts,value);
    }

    get phraseOWordKeyIdxPair() {
        return this._startWordMark.startIdx + "_" + this._endWordMark.startIdx;
    }

    // set phraseOWordKeyIdxPair(value) {
    //     this._phraseOWordKeyIdxPair = value;
    // }

    @Expose()
    get startWordMark() {
        return this._startWordMark;
    }

    @Type(()=>PhraseOWordUsage.WordMark)
    set startWordMark(value) {
        // console.log("setting startWordMark",value);
        this._startWordMark = value;
    }

    @Expose()
    get endWordMark() {
        return this._endWordMark;
    }

    @Type(()=>PhraseOWordUsage.WordMark)
    set endWordMark(value) {
        // console.log("setting endWordMark",value);
        this._endWordMark = value;
    }



    // get ofThisUsageSentece() {
    //     return this._ofThisUsageSentece;
    // }
    //
    // set ofThisUsageSentece(value) {
    //     this._ofThisUsageSentece = value;
    // }

    get isStartWordMarkValid() {
        return this._startWordMark.startIdx !== -1;
    }

    get phraseOWordStartIndex() {
        let startIndex = -1;
        if (this._isValidPhraseOWord) {
            startIndex = this._startWordMark.startIdx;
        }

        return startIndex;
    }

    get phraseOWordEndIndex() {
        let endIndex = -1;
        if (this._isValidPhraseOWord) {
            endIndex = this._endWordMark.startIdx + this._endWordMark.word.length;
        }
        return endIndex;
    }

    // get phraseOWordKeyIdxPair() {
    //     return this.phraseOWordKeyIdxPair;
    // }


    get wordOrPhrase(){
        let result = 'invalid';
        if(this._startWordMark?.startIdx!==-1&&this._endWordMark?.startIdx!==-1){
            if(this._startWordMark?.startIdx===this._endWordMark?.startIdx){
                result = "word";
            }else{
                result = "phrase";
            }
        }
        return result;
    }

    @Expose
    get phraseOWordText(){
        return this?.liju.eng.substring(this.phraseOWordStartIndex,this.phraseOWordEndIndex);
    }
    clone() {
        let theCLone = new PhraseOWordUsage.PhraseOWord(this._startWordMark.clone(), this._endWordMark.clone(), this._liju, this._isValidPhraseOWord);
        // theCLone.liju = this.liju;
        return theCLone;
        // return theCLone.ofThisUsageSentece = this.ofThisUsageSentece;
    }
}

PhraseOWordUsage.Word = class extends PhraseOWordUsage.PhraseOWord{

    _selectedFormsCounts;
    constructor(startWordMark, endWordMark, liju, isValidPhraseOWord) {
        super(startWordMark, endWordMark, liju, isValidPhraseOWord);
        this._selectedFormsCounts=[];
    }
    @Expose()
    get selectedFormsCounts() {
        return this._selectedFormsCounts;
    }

    set selectedFormsCounts(value) {
        clearAndPushAll(this._selectedFormsCounts,value)
    }

    clone() {
        let theCLone = new PhraseOWordUsage.Word(this._startWordMark.clone(), this._endWordMark.clone(), this._liju, this._isValidPhraseOWord);
        // theCLone.liju = this.liju;
        return theCLone;
        // return theCLone.ofThisUsageSentece = this.ofThisUsageSentece;
    }
}

PhraseOWordUsage.Phrase = class extends PhraseOWordUsage.PhraseOWord{

    @Type(()=>PhraseOWordUsage.Phrase)
    _subPhrases;
    constructor(startWordMark, endWordMark, liju, isValidPhraseOWord) {
        super(startWordMark, endWordMark, liju, isValidPhraseOWord);
        this._subPhrases=[]
    }


    @Expose()
    get subPhrases() {
        return this._subPhrases;
    }

    @Type(()=>PhraseOWordUsage.Phrase)
    set subPhrases(value) {
        //todo 20240310 设置对应liju属性
        this._subPhrases = value;
    }

    clone() {
        let theCLone = new PhraseOWordUsage.Phrase(this._startWordMark.clone(), this._endWordMark.clone(), this._liju, this._isValidPhraseOWord);
        // theCLone.liju = this.liju;
        return theCLone;
        // return theCLone.ofThisUsageSentece = this.ofThisUsageSentece;
    }
}

// @Exclude()
PhraseOWordUsage.WordMark = class{

    _startIdx;
    _word;

    constructor(startIdx, word) {
        if (startIdx !== undefined) {
            this._startIdx = startIdx;
            this._word = word;
        } else {
            this.initIndex();
        }
        this._startIdx = startIdx;
        this._word = word;
    }

    toPersistRaw(){
        let resultObj = {};
        assignIn(resultObj,this);
        return resultObj;
    }

    initIndex() {
        this._word = null;
        this._startIdx = -1;
    }

    clone() {
        return new PhraseOWordUsage.WordMark(this.startIdx, String(this.word));
    }

    @Expose()
    get startIdx() {
        return this._startIdx;
    }

    @Expose()
    set startIdx(value) {
        this._startIdx = value;
    }

    @Expose()
    get word() {
        return this._word;
    }

    @Expose()
    set word(value) {
        this._word = value;
    }
}

PhraseOWordUsage.WordSpanNode = class {

    /**
     *
     * @param node the html dom
     * @param word
     * @param idx
     */
    constructor(node, word, idx) {
        this._word = word;
        this._idx = idx;
        this._node = node;
    }

    get node() {
        return this._node;
    }

    set node(value) {
        this._node = value;
    }

    get word() {
        return this._word;
    }

    get idx() {
        return this._idx;
    }
}

PhraseOWordUsage.WORDIDX_ATTR = "wordIdx";
// PhraseOWordUsage.SENTENCEIDX_ATTR = "sentenceIdx";
PhraseOWordUsage.LANGSECTION_ATTR = "langsection";
PhraseOWordUsage.TEMPCURRPHRASEOWORD_ATTR = "tempCurrPhraseOWord";
PhraseOWordUsage.WORDBOLD_ATTR = "wordBold";

PhraseOWordUsage.PhraseOWordArray = class extends Array {

    static createFromObject(obj) {
        let thePhrasesOWords = new PhraseOWordUsage.PhraseOWordArray();
        Object.assign(thePhrasesOWords, obj)
    }

    findByPhraseOWord(thePhraseOWord) {
        let found = super.find(function (value) {
            return PhraseOWordUsage.PhraseOWordArray.isEquals(thePhraseOWord, value);
        }, thePhraseOWord);
        return found;
    }

    remove(thePrase) {
        let theIdx = super.findIndex(function (value) {
            return PhraseOWordUsage.PhraseOWordArray.isEquals(thePrase, value);
        }, thePrase);

        if (theIdx !== -1) {
            return super.splice(theIdx, 1);
        }
    }

    findIndexByPhraseOWord(thePhraseOWord) {
        return super.findIndex(function (value) {
            return PhraseOWordUsage.PhraseOWordArray.isEquals(thePhraseOWord, value);
        }, thePhraseOWord);
    }

    static isEquals(phraseOWordA, phraseOWordB) {
        return phraseOWordA.startWordMark.startIdx === phraseOWordB.startWordMark.startIdx && phraseOWordA.endWordMark.startIdx === phraseOWordB.endWordMark.startIdx;
    }
}


PhraseOWordUsage.BoldThePhrases = class {

    boldingPhrasesOWords;
    constructor() {
        /**
         *
         * @type {PhraseOWordUsage.PhraseOWordArray}
         */
        this.boldingPhrasesOWords = new PhraseOWordUsage.PhraseOWordArray();

        // /**
        //  *
        //  * @type {PhraseOWordUsage.PhraseOWord}
        //  */
        // this.currTempPhraseOWord = null;
        // this.pairIdxKeyMapping = {};
    }

    /**
     *
     * @param phraseOWord {PhraseOWordUsage.PhraseOWord}
     */
    addThePhraseOWordToPersist(phraseOWord) {
        if (phraseOWord.isValidPhraseOWord) {
            // new PhraseOWordUsage.PhraseOWord()
            // this.addToBoldPhraseOWord(this.currTempPhraseOWord.clone());
            this.boldingPhrasesOWords.push(phraseOWord.clone());
            // this.currTempPhraseOWord = null;
        }
    }

    removePhraseOWord(start, end) {
        this.boldingPhrasesOWords.remove(new PhraseOWordUsage.PhraseOWord(
            new PhraseOWordUsage.WordMark(start),
            new PhraseOWordUsage.WordMark(end),
            null,
            false));
    }

}

export default PhraseOWordUsage;